/*
 * Josh Lindoo
 * Login ID : lind6441
 * CS-102, Winter 2013
 * Programming Assignment 3
 * Database class: Storage for movies/showings, and methods for storing/using
 * 					those objects
 */

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;

public class Database {
	//List of movies
	public LinkedList <Movie>movieList = new LinkedList<Movie>();
	
	//Constructor
	public Database() {
		
	}
	
	
	/*
	 * Method: searchMovies
	 * Purpose: allow user to search for a specific movie title
	 * Parameters:
	 * 		String title:	title of movie to search for
	 * Returns: void
	 */
	
	public void searchMovies(String title) {
		Iterator <Movie>movieIterator = movieList.iterator();
		while(movieIterator.hasNext()) {
			Movie currMovie = movieIterator.next();
			if(currMovie.getTitle().equals(title)) { //if the titles match
				System.out.println(currMovie); //print movie
				
				//Show iterator
				Iterator <Showing>showIterator = currMovie.getShowList()
													.iterator();
				if(!showIterator.hasNext()) //if there aren't shows
					System.out.println("There are currently no showings for " +
							"this movie..");
				
				while(showIterator.hasNext()) { //print all of the shows
					System.out.println(showIterator.next());
				}
				return;
			}
		}
		System.out.println("No movie found..");
	}
	
	
	/*
	 * Method: storeMovies
	 * Purpose: parse the movie data from input file and save in db
	 * Parameters:
	 * 		Scanner fileScanner:	scanner of movie input file
	 * Returns: void
	 */
	
	public void storeMovies(Scanner fileScanner) {
		while(fileScanner.hasNextLine()) {	//while there are more lines
			
			final int MOVIE_FIELDS = 4; //number of fields in array
			String[] movieData = new String[MOVIE_FIELDS]; //array of movie data
			
			String line = fileScanner.nextLine(); //get the next line
			Scanner lineScanner = new Scanner(line); //most recent line scanner
			lineScanner.useDelimiter("/"); //using / as the delimiter
			
			int index = 0; //counter for while loop
			while(lineScanner.hasNext()) { //fill array with movie field data
				//try saving movie fields to array
				try {
					movieData[index] = lineScanner.next();
				}
				//if there are more than 4 fields in file
				catch (ArrayIndexOutOfBoundsException exc){
					System.out.println("Movie File: found entry with " +
							"invalid number of fields.");
					System.exit(0);
				}
				index++;
			}
			
			//if there were fewer than 4 fields exit
			if(index < 3) {
				System.out.println("Movie with fewer than 4 fields found");
				System.exit(0);
 			}
			
			lineScanner.close();
			Movie newMovie = new Movie(movieData); //create movie obj
			addMovie(newMovie); //add the movie to the database
		}
	}
	
	
	/*
	 * Method: usrAddMovie
	 * Purpose: allow user to manually add movies to db
	 * Parameters:
	 * 		Scanner console:	scanner of console input
	 * Returns: void
	 */
	
	public void usrAddMovie(Scanner console) {
		final int MOVIE_FIELDS = 4; //number of fields in array
		String[] movieData = new String[MOVIE_FIELDS]; //array of movie data
		
		String line = console.nextLine(); //get the next line
		Scanner lineScanner = new Scanner(line); //most recent line scanner
		lineScanner.useDelimiter("/"); //using / as the delimiter
		
		int index = 0; //counter for while loop
		while(lineScanner.hasNext()) { //fill array with movie field data
			//try saving movie fields to array
			try {
				movieData[index] = lineScanner.next();
			}
			//if there are more than 4 fields in file
			catch (ArrayIndexOutOfBoundsException exc){
				System.out.println("Movie File: found entry with " +
						"invalid number of fields.");
				System.exit(0);
			}
			
			index++;
		}
		
		//if there were fewer than 4 fields exit
		if(index < 3) {
			System.out.println("Movie with fewer than 4 fields found");
			System.exit(0);
			}
		
		lineScanner.close();
		Movie newMovie = new Movie(movieData); //create movie obj
		addMovie(newMovie); //add the movie to the database
	}
	
	
	/*
	 * Method: storeShowings
	 * Purpose: parse the showing data from input file and save in db
	 * Parameters:
	 * 		Scanner fileScanner:	scanner of showing input file
	 * Returns: void
	 */
	
	public void storeShowings(Scanner fileScanner) {
		while(fileScanner.hasNextLine()) {	//while there are more lines
			
			final int SHOWING_FIELDS = 3; //number of fields in array
			String[] showData = new String[SHOWING_FIELDS]; //array of show data
			
			String line = fileScanner.nextLine(); //get the next line
			Scanner lineScanner = new Scanner(line); //most recent line scanner
			lineScanner.useDelimiter("/"); //using / as the delimiter
			
			int index = 0; //counter for while loop
			while(lineScanner.hasNext()) { //fill array with showing field data
				//try saving showing fields to array
				try {
					showData[index] = lineScanner.next();
				}
				//if there are more than 3 fields in file
				catch (ArrayIndexOutOfBoundsException exc){
					System.out.println("Showing File: found entry with " +
							"invalid number of fields.");
					System.exit(0);
				}
				index++;
			}
			
			//if there were fewer than 3 fields exit
			if(index < 2) {
				System.out.println("Showing with fewer than 3 " +
						"fields found");
				System.exit(0);
			}
			
			lineScanner.close(); //close scanner
			Showing newShow = new Showing(showData); //create show obj
			addShow(newShow); //add the show to the database
		}
	}
	
	
	/*
	 * Method: usrAddShow
	 * Purpose: allow user to manually add a single show
	 * Parameters:
	 * 		Scanner console:	scanner of user input
	 * Returns: void
	 */
	
	public void usrAddShow(Scanner console) {
		final int SHOWING_FIELDS = 3; //fields in array
		String[] showData = new String[SHOWING_FIELDS]; //array of show data
		
		String line = console.nextLine(); //get the next line
		Scanner lineScanner = new Scanner(line); //most recent line scanner
		lineScanner.useDelimiter("/"); //using / as the delimiter
		
		int index = 0; //counter for while loop
		while(lineScanner.hasNext()) { //fill array with showing field data
			//try saving showing fields to array
			try {
				showData[index] = lineScanner.next();
			}
			//if there are more than 3 fields in file
			catch (ArrayIndexOutOfBoundsException exc){
				System.out.println("Showing File: found entry with " +
						"invalid number of fields.");
				System.exit(0);
			}
			index++;
		}
		
		//if there were fewer than 3 fields exit
		if(index < 2) {
			System.out.println("Showing with fewer than 3 " +
					"fields found");
			System.exit(0);
		}
		
		lineScanner.close(); //close scanner
		Showing newShow = new Showing(showData); //create show obj
		addShow(newShow); //add the show to the database
	}
	
	
	/*
	 * Method: addMovie
	 * Purpose: add movie to linked list
	 * Parameters: Movie newMovie: the movie obj to add
	 * Returns: void
	 */
	
	public void addMovie(Movie newMovie) {
		Iterator<Movie> iterator = movieList.iterator(); //movie iterator
		Movie current = null; //selected movie obj
		String newTitle = newMovie.getTitle(); //new title
		
		if(movieList.size() == 0) { //if the list is empty
			movieList.add(newMovie);
			return;
		}
		
		int index = 0; //track index
		while(iterator.hasNext()) {
			current = iterator.next();
			String currTitle = current.getTitle(); //selected's title
			
			int result = newTitle.compareToIgnoreCase(currTitle); //comp result
			
			if(result < 0) { //if the new movie comes before the next title
				movieList.add(index, newMovie);
				return;
			}
			else { //otherwise repeat
				index++;
			}
		}
		
		if(index == movieList.size()) { //end case
			movieList.add(index, newMovie);
		}
	}
	
	
	/*
	 * Method: addShow
	 * Purpose: add showing to linked list
	 * Parameters: Showing newShow: the showing obj to add
	 * Returns: void
	 */
	
	public void addShow(Showing newShow) {
		int matchIndex = idChecker(newShow.getID()); //index of matched ID
		Movie matched = null; //movie obj at matched ID index
		
		if(matchIndex == -1) //no matching movie
			System.out.println("Showing error: ID mismatch.. show skipped!");
		else {//set title if match found
			matched = movieList.get(matchIndex);
			newShow.setTitle(matched.getTitle());
			
			LinkedList <Showing>showList = matched.getShowList(); //LL of shows
			Showing current = null; //selected show obj
			
			if(showList.size() == 0) { //if the list is empty
				showList.add(newShow);
				return;
			}
			
			//Iterator of showlist
			Iterator<Showing> showIterator = showList.iterator();
			
			int index = 0; //track index
			while(showIterator.hasNext()) {
				current = showIterator.next();
				//If show comes before current show
				if(newShow.getFullTime() < current.getFullTime()) {
					showList.add(index, newShow);
					return;
				}
				else {
					index++;
				}
			}
			showList.add(index, newShow);
		}
	}
	
	
	/*
	 * Method: validateDB
	 * Purpose: Remove old movies and showings
	 * Parameters: 
	 * Returns: void
	 */
	public void validateDB(String dateStr) {
		int purgeDate = 0; //store purging date as int
		if(dateStr.length() != 8) { //check length
			System.out.println("Date error: invalid input length!");
			return;		
		}
		try { //check for not numerical characters
			purgeDate = Integer.parseInt(dateStr);
		}
		catch (NumberFormatException exc) {
			System.out.println("Date error: invalid characters in input!");
		}
		
		//Iterator of movieList
		Iterator <Movie>movieIterator = movieList.iterator();
		
		while(movieIterator.hasNext()) { //loop through movies
			
			Movie currMovie = movieIterator.next(); //track curr movie
			
			//LL of shows
			LinkedList <Showing>showList = currMovie.getShowList();
			//showList iterator
			Iterator <Showing>showIterator = showList.iterator(); 
			Showing currShow = null; //track current show
			
			while(showIterator.hasNext()) { //loop through shows
				currShow = showIterator.next();
				long currDate = currShow.getDate(); //store date of currShow
				if(currDate < purgeDate) { //if show is old.. remove
					System.out.println("Show: " + currShow + " has been removed..");
					showIterator.remove(); 
				}
			}
			
			if(showList.size() == 0) { //if showlist is empty.. remove movie
				System.out.println("Movie: " + currMovie + " has been removed..");
				movieIterator.remove();
			}
		}
	}
	
	
	/*
	 * Method: idChecker
	 * Purpose: checks for matching ids in db
	 * Parameters: int newID: the id to check
	 * Returns: int: index of match or -1 if no match
	 */
	
	public int idChecker(int newID) {
		Iterator<Movie> iterator = movieList.iterator(); //iterator
		int index = 0; //track index
		while(iterator.hasNext()) {
			Movie selected = iterator.next(); //selected movie
			if(newID == selected.getID()) return index; //match found
			index++;
		}
		return -1; //no match found
	}
	
	
	/*
	 * Method: printAll
	 * Purpose: Print all movies and shows
	 * Parameters: none
	 * Returns: void
	 */
	
	public void printAll() {
		//Movie Iterator
		Iterator<Movie> movieIterator = movieList.iterator();
		
		if(!movieIterator.hasNext())
			System.out.println("No movies or showingss in the database..");
		
		//While there are more movies
		while(movieIterator.hasNext()) {
			Movie currMovie = movieIterator.next(); //track current movie
			LinkedList <Showing>showList = currMovie.getShowList(); //show list
			Iterator<Showing> showIterator = showList.iterator(); // show iter.
			
			System.out.println("\n" + currMovie); //print movie title
			System.out.println("--------------------"); //spacer
			
			//If no showings for given movie
			if(!showIterator.hasNext())
				System.out.println("No showings..");
			
			//While more shows
			while(showIterator.hasNext()) {
				System.out.println(showIterator.next()); //print shows
			}
		}
	}
}
